import * as Clipboard from 'clipboard'
import axios from 'axios'
import { JS_TYPE } from '@/utils/constants'
import XEUtils from 'xe-utils'
import request from '@/api'
import { getFileInfo } from '@/api/form'
import { isEmpty } from 'lodash-es'

export function isNull(value) {
  return value === null || value === undefined
}

export function isNotNull(value) {
  return value !== null && value !== undefined
}

export function isEmptyStr(str) {
  //return (str === undefined) || (!str) || (!/[^\s]/.test(str));
  return str === undefined || (!str && str !== 0 && str !== '0') || !/[^\s]/.test(str)
}

export const generateId = function() {
  return Math.floor(Math.random() * 100000 + Math.random() * 20000 + Math.random() * 5000)
}

export const deepClone = function(origin) {
  if (origin === undefined) {
    return undefined
  }

  return JSON.parse(JSON.stringify(origin))
}

export const overwriteObj = function(obj1, obj2) {
  /* 浅拷贝对象属性，obj2覆盖obj1 */
  Object.keys(obj2).forEach((prop) => {
    obj1[prop] = obj2[prop]
  })
}

/**
 * 用Function对象实现eval函数功能
 * @param fn 函数体代码
 * @param DSV DSV变量
 * @param VFR 表单组件
 * @param formulaJs formula-js对象
 * @returns {*}
 */
export const evalFn = function(fn, DSV = null, VFR = null, formulaJs = null) {
  let f = new Function('DSV', 'VFR', 'LS', 'formulaJs', 'return ' + fn)
  return f(DSV, VFR, localStorage, formulaJs)
}

export const trimEx = function(str, char, type) {
  if (char) {
    if (type === 'left') {
      return str.replace(new RegExp('^\\' + char + '+', 'g'), '')
    } else if (type === 'right') {
      return str.replace(new RegExp('\\' + char + '+$', 'g'), '')
    }

    return str.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '')
  }

  return str.replace(/^\s+|\s+$/g, '')
}

export const hasPropertyOfObject = function(obj, propPath) {
  const keys = propPath.split('.')
  let tmpObj = obj
  let result = true

  for (const key of keys) {
    if (!tmpObj.hasOwnProperty(key)) {
      result = false
      break
    } else {
      tmpObj = tmpObj[key]
    }
  }

  return result
}

export const objectKeysToArray = function(obj) {
  if (!obj) return []

  const resultArray = []
  Object.keys(obj).forEach((key) => {
    resultArray.push(key)
  })

  return resultArray
}

function isDef(value) {
  return value !== undefined && value !== null
}

/*export const getObjectValue = function (obj, propPath) {
  const keys = propPath.split('.')
  let result = obj

  keys.forEach(key => {
    result = isDef(result) && isDef(result[key]) ? result[key] : null
  })

  return result
}*/

/*export const setObjectValue = function (obj, objectName, value) {
  const objectChains = objectName.split('.')
  let objectModel = obj

  objectChains.forEach((key, idx) => {
    if (!key) return

    if (idx === objectChains.length - 1) {
      objectModel[key] = value
      return
    }

    if (objectModel[key] === undefined) {
      objectModel[key] = {}
    }
    objectModel = objectModel[key]
  })
}*/

export const addWindowResizeHandler = function(handler) {
  let oldHandler = window.onresize
  if (typeof window.onresize != 'function') {
    window.onresize = handler
  } else {
    window.onresize = function() {
      oldHandler()
      handler()
    }
  }
}

const createStyleSheet = function() {
  let head = document.head || document.getElementsByTagName('head')[0]
  let style = document.createElement('style')
  style.type = 'text/css'
  head.appendChild(style)
  return style.sheet
}

export const insertCustomCssToHead = function(cssCode, formId = '') {
  // console.log('insertCustomCssToHead');
  const head = document.getElementsByTagName('head')[0]
  let oldStyle = document.getElementById('vform-custom-css')
  if (!!oldStyle) {
    head.removeChild(oldStyle) //先清除后插入！！
  }
  if (!!formId) {
    oldStyle = document.getElementById('vform-custom-css' + '-' + formId)
    !!oldStyle && head.removeChild(oldStyle) //先清除后插入！！
  }

  let newStyle = document.createElement('style')
  newStyle.type = 'text/css'
  newStyle.rel = 'stylesheet'
  newStyle.id = !!formId ? 'vform-custom-css' + '-' + formId : 'vform-custom-css'
  try {
    newStyle.appendChild(document.createTextNode(cssCode))
  } catch (ex) {
    newStyle.styleSheet.cssText = cssCode
  }

  head.appendChild(newStyle)
}

export const insertGlobalFunctionsToHtml = function(functionsCode, formId = '') {
  // console.log('insertGlobalFunctionsToHtml');
  // const bodyEle = document.getElementsByTagName('body')[0]
  const bodyEle = document.childNodes[0].childNodes[1]
  let oldScriptEle = document.scripts['v_form_global_functions']
  !!oldScriptEle && bodyEle.removeChild(oldScriptEle) //先清除后插入！！
  if (!!formId) {
    oldScriptEle = document.scripts['v_form_global_functions' + '-' + formId]
    !!oldScriptEle && bodyEle.removeChild(oldScriptEle) //先清除后插入！！
  }

  let newScriptEle = document.createElement('script')
  newScriptEle.id = !!formId ? 'v_form_global_functions' + '-' + formId : 'v_form_global_functions'
  newScriptEle.type = 'text/javascript'
  newScriptEle.innerHTML = functionsCode
  bodyEle.appendChild(newScriptEle)
}

export const deleteCustomStyleAndScriptNode = function(previewState, formId) {
  const head = document.getElementsByTagName('head')[0]
  let oldStyle = document.getElementById('vform-custom-css' + '-' + formId)
  if (previewState) {
    oldStyle = document.getElementById('vform-custom-css')
  }
  if (!!oldStyle) {
    head.removeChild(oldStyle)
  }

  const bodyEle = document.getElementsByTagName('body')[0]
  let oldScriptEle = document.getElementById('v_form_global_functions' + '-' + formId)
  if (previewState) {
    oldScriptEle = document.getElementById('v_form_global_functions')
  }
  if (!!oldScriptEle) {
    bodyEle.removeChild(oldScriptEle)
  }
}

export const optionExists = function(optionsObj, optionName) {
  if (!optionsObj) {
    return false
  }

  return Object.keys(optionsObj).indexOf(optionName) > -1
}

export const loadRemoteScript = function(srcPath, callback) {
  /*加载远程js，加载成功后执行回调函数*/
  let sid = encodeURIComponent(srcPath)
  let oldScriptEle = document.getElementById(sid)

  if (!oldScriptEle) {
    let s = document.createElement('script')
    s.src = srcPath
    s.id = sid
    document.body.appendChild(s)

    s.onload = s.onreadystatechange = function(_, isAbort) {
      /* 借鉴自ace.js */
      if (isAbort || !s.readyState || s.readyState === 'loaded' || s.readyState === 'complete') {
        s = s.onload = s.onreadystatechange = null
        if (!isAbort) {
          callback()
        }
      }
    }
  }
}

export function traverseFieldWidgets(
  widgetList,
  handler,
  parent = null,
  staticWidgetsIncluded = false,
) {
  if (!widgetList) {
    return
  }

  widgetList.map((w) => {
    if (w.formItemFlag || (w.formItemFlag === false && staticWidgetsIncluded)) {
      handler(w, parent)
    } else if (w.type === 'grid') {
      w.cols.map((col) => {
        traverseFieldWidgets(col.widgetList, handler, w, staticWidgetsIncluded)
      })
    } else if (w.type === 'table') {
      w.rows.map((row) => {
        row.cols.map((cell) => {
          traverseFieldWidgets(cell.widgetList, handler, w, staticWidgetsIncluded)
        })
      })
    } else if (w.type === 'tab') {
      w.tabs.map((tab) => {
        traverseFieldWidgets(tab.widgetList, handler, w, staticWidgetsIncluded)
      })
    } else if (w.type === 'sub-form' || w.type === 'grid-sub-form') {
      traverseFieldWidgets(w.widgetList, handler, w, staticWidgetsIncluded)
    } else if (w.category === 'container') {
      //自定义容器
      traverseFieldWidgets(w.widgetList, handler, w, staticWidgetsIncluded)
    }
  })
}

export function traverseContainerWidgets(widgetList, handler) {
  if (!widgetList) {
    return
  }

  widgetList.map((w) => {
    if (w.category === 'container') {
      handler(w)
    }

    if (w.type === 'grid' || w.type === 'grid-adv') {
      w.cols.map((col) => {
        traverseContainerWidgets(col.widgetList, handler)
      })
    } else if (w.type === 'table') {
      w.rows.map((row) => {
        row.cols.map((cell) => {
          traverseContainerWidgets(cell.widgetList, handler)
        })
      })
    } else if (w.type === 'tab') {
      w.tabs.map((tab) => {
        traverseContainerWidgets(tab.widgetList, handler)
      })
    } else if (w.type === 'sub-form' || w.type === 'grid-sub-form') {
      traverseContainerWidgets(w.widgetList, handler)
    } else if (w.category === 'container') {
      //自定义容器
      traverseContainerWidgets(w.widgetList, handler)
    }
  })
}

export function traverseAllWidgets(widgetList, handler) {
  if (!widgetList) {
    return
  }

  widgetList.map((w) => {
    handler(w)

    if (w.type === 'grid' || w.type === 'grid-adv') {
      w.cols.map((col) => {
        handler(col)
        traverseAllWidgets(col.widgetList, handler)
      })
    } else if (w.type === 'table') {
      w.rows.map((row) => {
        row.cols.map((cell) => {
          handler(cell)
          traverseAllWidgets(cell.widgetList, handler)
        })
      })
    } else if (w.type === 'tab') {
      w.tabs.map((tab) => {
        traverseAllWidgets(tab.widgetList, handler)
      })
    } else if (w.type === 'sub-form' || w.type === 'grid-sub-form') {
      traverseAllWidgets(w.widgetList, handler)
    } else if (w.category === 'container') {
      //自定义容器
      traverseAllWidgets(w.widgetList, handler)
    }
  })
}

function handleWidgetForTraverse(widget, handler) {
  if (!!widget.category && widget.category === 'container') {
    traverseFieldWidgetsOfContainer(widget, handler)
  } else if (widget.formItemFlag) {
    handler(widget)
  }
}

/**
 * 遍历容器内的字段组件
 * @param con
 * @param handler
 */
export function traverseFieldWidgetsOfContainer(con, handler) {
  if (con.type === 'grid' || w.type === 'grid-adv') {
    con.cols.forEach((col) => {
      col.widgetList.forEach((cw) => {
        handleWidgetForTraverse(cw, handler)
      })
    })
  } else if (con.type === 'table') {
    con.rows.forEach((row) => {
      row.cols.forEach((cell) => {
        cell.widgetList.forEach((cw) => {
          handleWidgetForTraverse(cw, handler)
        })
      })
    })
  } else if (con.type === 'tab') {
    con.tabs.forEach((tab) => {
      tab.widgetList.forEach((cw) => {
        handleWidgetForTraverse(cw, handler)
      })
    })
  } else if (con.type === 'sub-form' || con.type === 'grid-sub-form') {
    con.widgetList.forEach((cw) => {
      handleWidgetForTraverse(cw, handler)
    })
  } else if (con.category === 'container') {
    //自定义容器
    con.widgetList.forEach((cw) => {
      handleWidgetForTraverse(cw, handler)
    })
  }
}

function handleContainerTraverse(widget, fieldHandler, containerHandler) {
  if (!!widget.category && widget.category === 'container') {
    traverseWidgetsOfContainer(widget, fieldHandler, containerHandler)
  } else if (widget.formItemFlag) {
    fieldHandler(widget)
  }
}

/**
 * 遍历容器内部的字段组件和容器组件
 * @param con
 * @param fieldHandler
 * @param containerHandler
 */
export function traverseWidgetsOfContainer(con, fieldHandler, containerHandler) {
  if (con.category === 'container') {
    containerHandler(con)
  }

  if (con.type === 'grid' || con.type === 'grid-adv') {
    con.cols.forEach((col) => {
      col.widgetList.forEach((cw) => {
        handleContainerTraverse(cw, fieldHandler, containerHandler)
      })
    })
  } else if (con.type === 'table') {
    con.rows.forEach((row) => {
      row.cols.forEach((cell) => {
        cell.widgetList.forEach((cw) => {
          handleContainerTraverse(cw, fieldHandler, containerHandler)
        })
      })
    })
  } else if (con.type === 'tab') {
    con.tabs.forEach((tab) => {
      tab.widgetList.forEach((cw) => {
        handleContainerTraverse(cw, fieldHandler, containerHandler)
      })
    })
  } else if (con.type === 'sub-form' || con.type === 'grid-sub-form') {
    con.widgetList.forEach((cw) => {
      handleContainerTraverse(cw, fieldHandler, containerHandler)
    })
  } else if (con.category === 'container') {
    //自定义容器
    con.widgetList?.forEach((cw) => {
      handleContainerTraverse(cw, fieldHandler, containerHandler)
    })
  }
}


/**
 * 获取所有字段组件
 * @param widgetList
 * @param staticWidgetsIncluded 是否包含按钮等静态组件，默认不包含
 * @returns {[]}
 */
export function getAllFieldWidgets(widgetList, staticWidgetsIncluded = false) {
  if (!widgetList) {
    return []
  }

  let result = []
  let handlerFn = (w) => {
    result.push({
      type: w.type,
      name: w.options.name,
      field: w,
    })
  }
  traverseFieldWidgets(widgetList, handlerFn, null, staticWidgetsIncluded)

  return result
}

/**
 * 获取所有容器组件
 * @param widgetList
 * @returns {[]}
 */
export function getAllContainerWidgets(widgetList) {
  if (!widgetList) {
    return []
  }

  let result = []
  let handlerFn = (w) => {
    result.push({
      type: w.type,
      name: w.options.name,
      container: w,
    })
  }
  traverseContainerWidgets(widgetList, handlerFn)

  return result
}

export function getFieldWidgetByName(widgetList, fieldName, staticWidgetsIncluded) {
  if (!widgetList) {
    return null
  }

  let foundWidget = null
  let handlerFn = (widget) => {
    if (widget.options.name === fieldName) {
      foundWidget = widget
    }
  }

  traverseFieldWidgets(widgetList, handlerFn, null, staticWidgetsIncluded)
  return foundWidget
}

export function getFieldWidgetById(widgetList, fieldId, staticWidgetsIncluded) {
  if (!widgetList) {
    return null
  }

  let foundWidget = null
  let handlerFn = (widget) => {
    if (widget.id === fieldId) {
      foundWidget = widget
    }
  }

  traverseFieldWidgets(widgetList, handlerFn, null, staticWidgetsIncluded)
  return foundWidget
}

export function getContainerWidgetByName(widgetList, containerName) {
  if (!widgetList) {
    return null
  }

  let foundContainer = null
  let handlerFn = (con) => {
    if (con.options.name === containerName) {
      foundContainer = con
    }
  }

  traverseContainerWidgets(widgetList, handlerFn)
  return foundContainer
}

export function getContainerWidgetById(widgetList, containerId) {
  if (!widgetList) {
    return null
  }

  let foundContainer = null
  let handlerFn = (con) => {
    if (con.id === containerId) {
      foundContainer = con
    }
  }

  traverseContainerWidgets(widgetList, handlerFn)
  return foundContainer
}

export function copyToClipboard(content, clickEvent, $message, successMsg, errorMsg) {
  const clipboard = new Clipboard(clickEvent.target, {
    text: () => content,
  })

  clipboard.on('success', () => {
    $message.success(successMsg)
    clipboard.destroy()
  })

  clipboard.on('error', () => {
    $message.error(errorMsg)
    clipboard.destroy()
  })

  clipboard.onClick(clickEvent)
}

export function getQueryParam(variable) {
  let query = window.location.search.substring(1)
  let vars = query.split('&')
  for (let i = 0; i < vars.length; i++) {
    let pair = vars[i].split('=')
    if (pair[0] == variable) {
      return pair[1]
    }
  }

  return undefined
}

/**
 * @return {FormConfig} 包含表单默认配置的对象
 */
export function getDefaultFormConfig() {
  return {
    modelName: 'formData',
    refName: 'vForm',
    rulesName: 'rules',
    labelWidth: 80,
    labelPosition: 'left',
    modelSelect: '',
    modelSelectTree: [], // 全局设置 model模型树
    modelFormTree: [], // 全局设置 model 表单模型 树
    size: '',
    labelAlign: 'label-left-align',
    cssCode: '',
    customClass: [],
    functions: '', //全局函数
    layoutType: 'PC',
    jsonVersion: 3,
    dataSources: [], //数据源集合
    serviceVersionVOs: [],//与表单绑定的服务版本对象集合
    service: {
      enabled: false,
      key: '',
    },
    onFormCreated: '',
    onFormMounted: '',
    onFormDataChange: '',
    onFormValidate: '',
  }
}

export function buildDefaultFormJson() {
  return {
    widgetList: [],
    formConfig: deepClone(getDefaultFormConfig()),
  }
}

export function cloneFormConfigWithoutEventHandler(formConfig) {
  let newFC = deepClone(formConfig)
  newFC.onFormCreated = ''
  newFC.onFormMounted = ''
  newFC.onFormDataChange = ''
  newFC.onFormValidate = ''

  return newFC
}

/**
 * 转译选择项数据
 * @param rawData
 * @param widgetType
 * @param labelKey
 * @param valueKey
 * @returns {[]}
 */
export function translateOptionItems(rawData, widgetType, labelKey, valueKey) {
  console.log('translateOptionItems')
  if (widgetType === 'cascader') {
    // 级联选择不转译
    return deepClone(rawData)
  }

  let result = []
  if (!!rawData && rawData.length > 0) {
    rawData.forEach((ri) => {
      if (ri.hasOwnProperty('disabled')) {
        result.push({
          label: ri[labelKey],
          value: ri[valueKey],
          item: ri,
          disabled: ri['disabled'],
        })
      } else {
        result.push({
          label: ri[labelKey],
          value: ri[valueKey],
          item: ri,
        })
      }
    })
  }

  return result
}

/**
 * 组装axios请求配置参数
 * @param arrayObj
 * @param DSV
 * @param VFR
 * @returns {{}}
 */
export function assembleAxiosConfig(arrayObj, DSV, VFR) {
  let result = {}
  if (!arrayObj || arrayObj.length <= 0) {
    return result
  }

  arrayObj.map((ai) => {
    if (ai.type === 'String') {
      result[ai.name] = String(ai.value)
    } else if (ai.type === 'Number') {
      result[ai.name] = Number(ai.value)
    } else if (ai.type === 'Boolean') {
      if (ai.value.toLowerCase() === 'false' || ai.value === '0') {
        result[ai.name] = false
      } else if (ai.value.toLowerCase() === 'true' || ai.value === '1') {
        result[ai.name] = true
      } else {
        result[ai.name] = null
      }
    } else if (ai.type === 'Variable') {
      result[ai.name] = evalFn(ai.value, DSV, VFR)
    }
  })

  /* 加入如下两行日志打印代码，是为了防止编译打包时DSV、VFR参数被剔除！！ begin */
  /* DSV、VFR入参没有在本函数中直接使用到，但在eval表达式中可能被使用到，故需确保DSV、VFR参数始终存在！！ */
  console.log('test DSV: ', DSV)
  console.log('test VFR: ', VFR)
  /* 加入如下两行日志打印代码，是为了防止编译打包时DSV、VFR入参会被剔除！！ end */

  return result
}

function buildRequestConfig(dataSource, DSV, VFR, isSandbox) {
  let config = {}
  if (dataSource.requestURLType === 'String') {
    config.url = dataSource.requestURL
  } else {
    config.url = evalFn(dataSource.requestURL, DSV, VFR)
  }
  config.method = dataSource.requestMethod

  config.headers = assembleAxiosConfig(dataSource.headers, DSV, VFR)
  config.params = assembleAxiosConfig(dataSource.params, DSV, VFR)
  config.data = assembleAxiosConfig(dataSource.data, DSV, VFR)

  let chFn = new Function('config', 'isSandbox', 'DSV', 'VFR', dataSource.configHandlerCode)
  return chFn.call(null, config, isSandbox, DSV, VFR)
}

export async function runDataSourceRequest(dataSource, DSV, VFR, isSandbox, $message) {
  try {
    let requestConfig = buildRequestConfig(dataSource, DSV, VFR, isSandbox)
    //console.log('test------', requestConfig)
    let result = await axios.request(requestConfig)
    //let result = await axios.create().request(requestConfig)

    let dhFn = new Function('result', 'isSandbox', 'DSV', 'VFR', dataSource.dataHandlerCode)
    return dhFn.call(null, result, isSandbox, DSV, VFR)
  } catch (err) {
    let ehFn = new Function(
      'error',
      'isSandbox',
      'DSV',
      '$message',
      'VFR',
      dataSource.errorHandlerCode,
    )
    console.error(err)
    return ehFn.call(null, err, isSandbox, DSV, $message, VFR)
  }
}

/**
 * 根据服务key或者keys获取服务对象
 * @param formConfig
 * @param serviceKey
 * @returns {null}
 */
export function getServiceById(formConfig, svvoId) {
  let resultService = null
  if (!!svvoId && !!formConfig.serviceVersionVOs) {
    if (XEUtils.isArray(svvoId)) {
      resultService = formConfig.serviceVersionVOs.filter((svvo) => svvoId.includes(svvo.id))
    } else {
      resultService = formConfig.serviceVersionVOs.find((svvo) => svvo.id == svvoId)
    }
  }

  if (!resultService) {
    console.error('Service not found: ' + svvoId)
  }
  return resultService
}

export function getDSByName(formConfig, dsName) {
  let resultDS = null
  if (!!dsName && !!formConfig.dataSources) {
    formConfig.dataSources.forEach((ds) => {
      if (ds.uniqueName === dsName) {
        resultDS = ds
      }
    })
  }

  if (!resultDS) {
    console.error('DS not found: ' + dsName)
  }

  return resultDS
}

export const generateUUID = () => {
  let d = new Date().getTime()
  const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = (d + Math.random() * 16) % 16 | 0
    d = Math.floor(d / 16)
    return (c == 'x' ? r : (r & 0x7) | 0x8).toString(16)
  })
  return uuid
}

//获取所有开启服务的组件
export function getAllServiceWidgets(widgetList) {
  const serviceWidgets = []
  traverseAllWidgets(widgetList, (widget) => {
    if (widget.options.service && widget.options.service.enabled) {
      serviceWidgets.push(widget)
    }
  })
  return serviceWidgets
}

export function getWidgetOrField(component) {
  return component.widget || component.field
}

export function getJSType(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1)
}

export function isNotEmpty(obj) {
  switch (getJSType(obj)) {
    case JS_TYPE.STRING:
      return obj.trim().length > 0
    case JS_TYPE.OBJECT:
      return Object.keys(obj).length > 0
    case JS_TYPE.ARRAY:
      return obj.length > 0
    default:
      return !!obj
  }
}

export function isTableById(id) {
  return id.includes('datatable')
}

export function getObjectValue(obj, key) {
  return XEUtils.get(obj, key)
}

export function setObjectValue(obj, key, value) {
  return XEUtils.set(obj, key, value)
}

export function traverseWidgetsOfDataTable(tableColumns, callback) {
  tableColumns.forEach((column) => {
    column.widgetList.forEach((widget) => callback(widget, column))
  })
}

export function findParents(array, code) {
  let parentArray = []

  if (array.length === 0) {
    return parentArray
  }

  function recursion(arrayNew, code) {
    for (let i = 0; i < arrayNew.length; i++) {
      let node = arrayNew[i]
      //当前选中code
      if (node.code === code) {
        parentArray.unshift(code)
        recursion(array, node.parentCode)
        break
      } else {
        if (!!node.children) {
          recursion(node.children, code)
        }
      }
    }
    return parentArray
  }

  parentArray = recursion(array, code)
  return parentArray
}

/**
 * 获取newList中不在于oldList中的元素
 * @param oldList 旧的列表
 * @param newList 新的列表
 * @param oldKey 旧数组需要对比的键
 * @param newKey 新数组需要对比的键
 */
export function getDiffElements(oldList, oldKey, newList, newKey) {
  if (!XEUtils.isArray(oldList)) {
    console.log('oldList is not array')
    return
  }
  if (!XEUtils.isArray(newList)) {
    console.log('newList is not array')
    return
  }
  if (oldList.length === 0) {
    return newList
  }
  if (newList.length === 0) {
    return []
  }
  return newList.filter(
    (newItem) => !oldList.find((oldItem) => oldItem[oldKey] === newItem[newKey]),
  )
}

/**
 * 将上传后返回的fileId转换为fileObj
 * @param uploadUrl
 * @param fileId
 * @returns {{url: string, status: string}}
 */
export const convertFileIdToFileObj = async (uploadUrl, fileId) => {
  const downloadUrl =
    window.location.origin +
    request.defaults.baseURL +
    uploadUrl.substring(0, uploadUrl.lastIndexOf('/')) +
    '/download?id=' +
    fileId
  try {
    const res = getFileInfo(fileId)
    return {
      name: res?.data?.fileName,
      uid: fileId,
      status: 'success',
      url: downloadUrl,
    }
  } catch (err) {
    throw new Error(`图片${fileId}不存在`)
  }
}

/**
 * 将树形结构的节点转换为路径映射
 *
 * 此函数通过递归遍历树形结构的节点，生成一个 Map 对象，
 * 其中每个节点的路径作为键，节点本身作为值，便于后续操作和查找
 *
 * @param {SchemaNode[]} nodes - 树形结构的节点数组
 * @param {string} parentPath - 当前父节点的路径，默认为空字符串
 * @param {Map} map - 用于存储节点路径和节点本身的 Map 对象，默认为新的 Map 实例
 * @returns {Map} - 包含所有节点路径及其对应节点的 Map 对象
 */
export function convertTreeToPathMap(nodes, parentPath = '', map = new Map(), level = 0) {
  // 遍历所有节点
  nodes.forEach((node, index) => {
    // 计算当前节点路径
    let currentPath
    if (parentPath === '') {
      // 根节点路径为索引（如 0）
      currentPath = `${index}`
    } else {
      // 子节点路径为父路径 + .children[索引]
      currentPath = `${parentPath}.children[${index}]`
    }

    // 将节点存入 Map，并添加 path 属性和 level 属性
    map.set(node.key, {
      label: node.label,
      path: currentPath,
      type: node.type,
      defaultValue: node.defaultValue,
      component: node.component,
      level: level, // 添加层级属性
    })

    // 递归处理子节点，层级加1
    if (node.children?.length > 0) {
      convertTreeToPathMap(node.children, currentPath, map, level + 1)
    }
  })
  // 返回路径映射
  return map
}

/**
 * 遍历树型结构并对每个节点执行回调函数
 *
 * @param tree 树型结构或节点
 * @param callback 对每个节点执行的回调函数
 * @param parentPath 当前节点的父路径，用于构建完整路径（内部使用）
 */
export function traverseTree(
  tree: any,
  callback: (node: any, path: string) => void,
  parentPath: string = '',
): void {
  // 处理数组类型的树
  if (Array.isArray(tree)) {
    tree.forEach((node, index) => {
      const currentPath = parentPath ? `${parentPath}[${index}]` : `${index}`
      // 对当前节点执行回调
      callback(node, currentPath)

      // 如果有子节点，递归处理
      if (node.children && Array.isArray(node.children)) {
        traverseTree(node.children, callback, `${currentPath}.children`)
      }
    })
  } else {
    // 处理单个节点
    const currentPath = parentPath || 'root'
    // 对当前节点执行回调
    callback(tree, currentPath)

    // 如果有子节点，递归处理
    if (tree.children && Array.isArray(tree.children)) {
      tree.children.forEach((child, index) => {
        const childPath = `${currentPath}.children[${index}]`
        callback(child, childPath)

        // 递归处理子节点的子节点
        if (child.children && Array.isArray(child.children)) {
          traverseTree(child.children, callback, `${childPath}.children`)
        }
      })
    }
  }
}

/**
 * 将树形结构数据转换为嵌套对象结构
 * @param treeData 树形数据数组
 * @returns 转换后的嵌套对象
 */
export const transformTreeToObject = (treeData: any[], getValue: (node: any) => any): Record<string, any> => {
  const result: Record<string, any> = {}

  const traverse = (nodes: any[], currentObject: Record<string, any>) => {
    nodes.forEach((node) => {
      // 如果是根节点，则直接遍历其子节点
      if (node.key === 'root' && node.children && node.children.length > 0) {
        traverse(node.children, currentObject)
      } else if (node.type === 'object' && node.children && node.children.length > 0) {
        // 如果是对象类型且有子节点，创建嵌套对象并递归
        currentObject[node.key] = {}
        traverse(node.children, currentObject[node.key])
      } else if (node.type === 'array') {
        // 如果是数组类型
        if (node.children && node.children.length > 0) {
          // 如果数组有子节点，创建一个包含单个对象的数组，递归处理子节点
          const arrayItemObject = {}
          traverse(node.children, arrayItemObject)
          currentObject[node.key] = [arrayItemObject]
        } else {
          // 如果数组没有子节点，创建一个空数组
          currentObject[node.key] = [getValue(node)]
        }
      } else if (node.key !== 'root') {
        // 对于非对象、非数组类型的节点或没有子节点的object节点（且非根节点）
        currentObject[node.key] = getValue(node)
      }
    })
  }

  traverse(treeData, result)

  // 返回构建好的对象
  return isEmpty(result) ? null : result
}

export function isSelectcy(type) {
  return type === 'select' || type === 'checkbox' || type==='radio'
}
